package luj.tool.jnproxyan.proxy.network.socks.cmd.connect2;

import io.netty.util.concurrent.GenericFutureListener;
import luj.bean.api.BeanContext;
import luj.bean.api.bean.Bean;
import luj.cluster.api.actor.Tellable;
import luj.net.api.client.ConnectionFactory;
import luj.tool.jnproxyan.proxy.network.socks.actor.root.message.request.connect.finish.ConnectFinishMsg;

/**
 * @see luj.tool.jnproxyan.proxy.network.direct.HttpsDirectConnector
 */
public class TargetServerConnector {

  public TargetServerConnector(ConnectionFactory connector, String targetHost, int targetPort, Tellable socksRef, Long reqId, BeanContext lujbean) {
    _connector = connector;
    _targetHost = targetHost;
    _targetPort = targetPort;
    _socksRef = socksRef;
    _reqId = reqId;
    _lujbean = lujbean;
  }

  /**
   * @see luj.tool.jnproxyan.proxy.network.socks.actor.root.message.request.connect.finish.OnConnectFinish#onHandle
   */
  public void connect() {
    ReqInfo reqInfo = new ReqInfo();
    reqInfo._reqId = _reqId;
    reqInfo._socksRef = _socksRef;
    reqInfo._lujbean = _lujbean;

    ConnectionFactory.ConnectFuture connectFuture = _connector.connect(c -> c
        .host(_targetHost) // .getHostAddress()
        .port(_targetPort)
        .connectTimeoutMillis(3000)
        .frameReceiver(new P2sReceive(reqInfo))
        .disconnectListener(new P2sDisconnect(reqInfo))
    );

    connectFuture.addListener(new GenericFutureListener<ConnectionFactory.ConnectFuture>() {
      @Override
      public void operationComplete(ConnectionFactory.ConnectFuture future) {
        Bean<ConnectFinishMsg> msg = _lujbean.createBean(ConnectFinishMsg.class);
        msg.setField(m -> m::reqId, _reqId);
        msg.setField(m -> m::targetHost, _targetHost);
        msg.setField(m -> m::targetPort, _targetPort);
        msg.setField(m -> m::connectResult, future);

        _socksRef.tell(msg.getValueInstance());
      }
    });
  }

  private final ConnectionFactory _connector;

  private final String _targetHost;
  private final int _targetPort;

  private final Tellable _socksRef;
  private final Long _reqId;

  private final BeanContext _lujbean;
}
